package com.green.common.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ObjectCompareUtil {

	/**
	 * 现在只是简单的实现了比较两个类型相同的javabean，
	 * 如果属性为List和Map现在还不能比较 。
	 * 
	 * @param arg0
	 *            旧对象，需要被比较的对象
	 *            配置了的属性必须实现了get方法，boolean类型的可以是is或get方法。参数为javabean
	 * @param arg1
	 *            新对象，用来与arg0比较
	 *            配置了的属性必须实现了get方法，boolean类型的可以是is或get方法。参数为javabean
	 * @param confMap
	 *            配置哪些属性应该比较,key为属性名，value为属性名对应的中文名。这里key对应的属性如果仍然为对象，
	 *            而又想比较其对象中的属性。则可以key可以用.来分隔取得。
	 *            如相比较：Person的address（为Address对象）属性中的name，则key可以为address.name
	 * @return
	 * @throws Exception
	 */
	public static List<Entry> compareObjects(Object arg0, Object arg1,
			Map<String, String> confMap) throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		if (null != confMap && !confMap.isEmpty()) {
			Class<?> classType = arg0.getClass();

			Field[] fields = classType.getDeclaredFields();

			Method[] methods = classType.getDeclaredMethods();
			Method method = null;

			List<Entry> list = new ArrayList<Entry>();
			String[] keyList = null;

			ObjectCompareUtil rt = new ObjectCompareUtil();
			Entry entry = null;

			Object oneReturn = null;
			Object otherReturn = null;
			String oneStr = null;
			String otherStr = null;

			String methodName = null;
			String fieldName = null;
			boolean isExists = false;

			for (String key : confMap.keySet()) {
				if (key.contains(".")) {
					keyList = key.split("\\.");
				}

				for (Field field : fields) {

					fieldName = field.getName();
					// 处理带.的
					if (keyList != null) {
						if (!keyList[0].equals(fieldName))
							continue;
						else {
							Field tempF = field;
							Method tempM = null;
							Class<?> tempC = classType;
							Object tempOne = arg0;
							Object tempOther = arg1;

							for (int i = 0; i < keyList.length; i++) {
								tempM = tempC.getMethod(
										"get"
												+ keyList[i].substring(0, 1)
														.toUpperCase()
												+ keyList[i].substring(1),
										new Class[] {});
								tempOne = tempM
										.invoke(tempOne, new Object[] {});
								// 返回为null的情况
								if (tempOne == null) {
									tempOne = tempM.getReturnType()
											.newInstance();
								}
								tempOther = tempM.invoke(tempOther,
										new Object[] {});
								if (tempOther == null) {
									tempOther = tempM.getReturnType()
											.newInstance();
								}
								tempF = tempC.getDeclaredField(keyList[i]);
								tempC = tempF.getType();
							}

							if (!String.valueOf(tempOne).equals(
									String.valueOf(tempOther))) {
								entry = rt.new Entry();
								entry.setName(confMap.get(key));
								entry.setOldValue(String.valueOf(tempOne));
								entry.setNewValue(String.valueOf(tempOther));
								list.add(entry);
								keyList = null;
							}else{
								keyList = null;
							}
						}
					} else {
						if (!key.equals(fieldName))
							continue;

						isExists = false;

						// boolean类型取值方法可以是is开头的也可以是get开头的
						if (field.getType().getSimpleName().toLowerCase()
								.equals("boolean")) {
							methodName = "is"
									+ key.substring(0, 1).toUpperCase()
									+ key.substring(1);
							for (Method mt : methods) {
								if (mt.getName().equals(methodName)) {
									isExists = true;
									break;
								}
							}
							if (!isExists) {
								methodName = "get"
										+ key.substring(0, 1).toUpperCase()
										+ key.substring(1);
							}
						} else {
							methodName = "get"
									+ key.substring(0, 1).toUpperCase()
									+ key.substring(1);
						}
						if (null != methodName) {

							method = classType.getDeclaredMethod(methodName,
									new Class[] {});

							oneReturn = method.invoke(arg0, new Object[] {});
							otherReturn = method.invoke(arg1, new Object[] {});

							oneStr = oneReturn == null ? "" : String.valueOf(oneReturn);
							otherStr = otherReturn == null ? "" : String.valueOf(otherReturn);
							// Date类型取值方法转换
							if (field.getType().getSimpleName().toLowerCase()
									.equals("date")) {
								oneStr = sdf.format(oneReturn);
								otherStr = sdf.format(otherReturn);
							}
							if (!oneStr.equals(otherStr)) {
								entry = new ObjectCompareUtil().new Entry();
								entry.setName(confMap.get(key));
								entry.setOldValue(oneStr);
								entry.setNewValue(otherStr);
								list.add(entry);
							}

						}
					}

				}

			}

			return list;
		} else {
			throw new Exception("属性配置不能为空");
		}
	}

	/**
	 * 现在只是简单的实现了比较两个list中ID相同的相同javaBean类型的对象。对于比较这个javaBean对象中的List、
	 * Map和其他javaBean对象类型的原生类型暂时未实现。
	 * 
	 * @param arg0
	 *            旧对象，需要被比较的对象 此list中的对象必须为javaBean。且属性有get方法，如果为boolean类型，可以为is方法
	 * @param arg1
	 *            新对象，用来与arg0比较 此list中的对象必须为javaBean。且属性有get方法，如果为boolean类型，可以为is方法
	 * @param confMap
	 *             配置哪些属性应该比较,key为属性名，value为属性名对应的中文名。这里key对应的属性如果仍然为对象，
	 *            而又想比较其对象中的属性。则可以key可以用.来分隔取得。
	 *            如相比较：Person的address（为Address对象）属性中的name，则key可以为address.name
	 * @return
	 * @throws Exception
	 */
	public static List<List<Entry>> compareList(List<?> arg0, List<?> arg1,
			Map<String, String> confMap) throws Exception {
		Object tempOne = null;
		Object tempTwo = null;
		String key = null;
		String value = null;
		String oneId = null;
		String twoId = null;

		List<List<Entry>> resultList = new ArrayList<List<Entry>>();
		List<Entry> entryList = null;

		Method method = null;
		Method idMethod = null;
		ObjectCompareUtil ref = new ObjectCompareUtil();
		Entry entry = null;

		if (arg0 != null && arg0.size() != 0) {
			tempOne = arg0.get(0);

			Class<?> classType = tempOne.getClass();

			idMethod = classType.getMethod("getId", new Class<?>[] {});

			if (arg1 != null && arg1.size() != 0) {
				Map<String, Map<String, Object>> addMap = new HashMap<String, Map<String, Object>>();// 判断是否在arg1中新增的元素
				Map<String, Object> addValue = null;// key为0在arg0中不存在 1为存在
				// 对象方法Map，这里应为只取javabean的get方法。所以不存在方法重名问题
				Map<String, Method> methodMap = new HashMap<String, Method>();

				for (Method m : classType.getDeclaredMethods()) {
					methodMap.put(m.getName(), m);
				}

				for (Object obj : arg0) {
					int count = 0;
					tempOne = idMethod.invoke(obj, new Object[] {});
					oneId = String.valueOf(tempOne);
					if (oneId != null) {
						for (Object obj1 : arg1) {
							tempTwo = idMethod.invoke(obj1, new Object[] {});
							twoId = String.valueOf(tempTwo);
							if (twoId == null)
								throw new Exception("对象必须有id值");

							if (!oneId.equals(twoId)) {
								addValue = addMap.get(twoId);
								if (addValue == null) {
									addValue = new HashMap<String, Object>();
									addValue.put("0", obj1);
									addMap.put(twoId, addValue);// 初始化为在arg0中不存在
								}

								count++;
								continue;
							}
							addValue = new HashMap<String, Object>();
							addValue.put("1", obj1);
							addMap.put(twoId, addValue);// 说明在arg0中也存在

							entryList = new ArrayList<Entry>();
							String[] fields = null;
							for (java.util.Map.Entry<String, String> keyEntry : confMap
									.entrySet()) {
								key = keyEntry.getKey();
								value = keyEntry.getValue();

								Map<String, Object> compareMap = getCompareObjectValue(
										key, classType, obj, obj1);
								tempOne = compareMap.get("one");
								tempTwo = compareMap.get("two");

								if (!String.valueOf(tempOne).equals(
										String.valueOf(tempTwo))) {
									// 这是这个元素被修改的情况
									entry = ref.new Entry();
									entry.setId(oneId);
									entry.setName(value);
									entry.setType(2);
									entry.setOldValue(String.valueOf(tempOne));
									entry.setNewValue(String.valueOf(tempTwo));
									entryList.add(entry);
								}
							}
							resultList.add(entryList);
						}
						if (count == arg1.size()) {
							entryList = new ArrayList<Entry>();
							for (java.util.Map.Entry<String, String> keyEntry : confMap
									.entrySet()) {
								key = keyEntry.getKey();
								value = keyEntry.getValue();
								
								tempOne = getSingleValue(key, classType, obj);
								// 这是这个元素被删除的情况
								entry = ref.new Entry();
								entry.setId(oneId);
								entry.setType(0);
								entry.setName(value);
								entry.setOldValue(String.valueOf(tempOne));
								entryList.add(entry);
							}
							resultList.add(entryList);
						}

					} else {
						throw new Exception("对象必须有id值");
					}

				}

				Object noObj = null;
				for (java.util.Map.Entry<String, Map<String, Object>> temp : addMap
						.entrySet()) {
					addValue = temp.getValue();
					for (java.util.Map.Entry<String, Object> et : addValue
							.entrySet()) {
						if (et.getKey().equals("0")) {
							entryList = new ArrayList<Entry>();
							for (java.util.Map.Entry<String, String> keyEntry : confMap
									.entrySet()) {
								key = keyEntry.getKey();
								value = keyEntry.getValue();
								noObj = et.getValue();
								
								noObj = getSingleValue(key, classType, noObj);
								// 这是新增元素的情况
								entry = ref.new Entry();
								entry.setId(et.getKey());
								entry.setType(1);
								entry.setName(value);
								entry.setNewValue(String.valueOf(noObj));
								entryList.add(entry);
							}
							resultList.add(entryList);
						}
					}
				}
			} else {
				idMethod = classType.getMethod("getId", new Class<?>[] {});
				for (Object obj : arg0) {
					tempOne = idMethod.invoke(obj, new Object[] {});
					oneId = String.valueOf(tempOne);
					if (null != oneId) {
						entryList = new ArrayList<Entry>();
						for (java.util.Map.Entry<String, String> keyEntry : confMap
								.entrySet()) {
							key = keyEntry.getKey();
							value = keyEntry.getValue();

							tempOne = getSingleValue(key, classType, obj);
							if (tempOne != null) {
								// 删除了全部原对象的情况
								entry = ref.new Entry();
								entry.setId(oneId);
								entry.setType(0);
								entry.setName(value);
								entry.setOldValue(String.valueOf(tempOne));
								entryList.add(entry);
							}
						}
						resultList.add(entryList);
					} else {
						throw new Exception("对象必须有id值");
					}
				}
			}

		} else {
			if (arg1 != null && arg1.size() != 0) {
				Class<?> classType = arg1.get(0).getClass();
				idMethod = classType.getMethod("getId", new Class<?>[] {});
				for (Object obj : arg1) {
					tempOne = idMethod.invoke(obj, new Object[] {});
					twoId = String.valueOf(tempOne);

					if (null != twoId) {
						entryList = new ArrayList<Entry>();
						for (java.util.Map.Entry<String, String> keyEntry : confMap
								.entrySet()) {
							key = keyEntry.getKey();
							value = keyEntry.getValue();

							tempOne = getSingleValue(key, classType, obj);
							if (tempOne != null) {
								// 这是全部都是新增的情况
								entry = ref.new Entry();
								entry.setId(twoId);
								entry.setType(1);
								entry.setName(value);
								entry.setNewValue(String.valueOf(tempOne));
								entryList.add(entry);
							}
						}
						resultList.add(entryList);
					} else {
						throw new Exception("对象必须有id值");
					}
				}
			} else {
				return null;
			}
		}

		return resultList;

	}

	public static String getDifferenceCompared(Object compared, Object compare,
			Map<String, String> configMap) throws Exception {

		List<Entry> entrys = compareObjects(compared, compare, configMap);

		if (entrys.size() == 0) {
			return null;
		}
		String result = "修改的属性有：";

		for (Entry entry : entrys) {
			result += entry.getName();
			result += ",由";
			if (null == entry.getOldValue() || entry.getOldValue().equals("")
					|| entry.getOldValue().equals("null")) {
				result += " 空 ";
			} else {
				result += entry.getOldValue();
			}

			result += "修改为";
			if (null == entry.getNewValue() || entry.getNewValue().equals("")
					|| entry.getNewValue().equals("null")) {
				result += " 空 ";
			} else {
				result += entry.getNewValue();
			}
			result += ";";
		}
		result = result.substring(0, result.length() - 1);
		return result;
	}

	public static List<String> getListCompareList(List<?> compared,
			List<?> compare, Map<String, String> configMap) throws Exception {
		List<String> resultList = new ArrayList<String>();

		List<List<Entry>> lists = compareList(compared, compare, configMap);

		for (List<Entry> list : lists) {

			if (list.size() != 0) {
				String temp = "";
				for (Entry entry : list) {
					if (entry.getType() == 0) {
						temp += "删除值为";
						temp += entry.getOldValue();
						temp += "的";
						temp += entry.getName() + ";";
					}
					if (entry.getType() == 1) {
						temp += "新增值为";
						temp += entry.getNewValue();
						temp += "的";
						temp += entry.getName() + ";";
					}
					if (entry.getType() == 2) {

						temp += "将";
						temp += entry.getName();
						temp += "的值由";

						if (null == entry.getOldValue()
								|| entry.getOldValue().equals("")
								|| entry.getOldValue().equals("null")) {
							temp += " 空 ";
						} else {
							temp += entry.getOldValue();
						}
						temp += "修改为";
						if (null == entry.getNewValue()
								|| entry.getNewValue().equals("")
								|| entry.getNewValue().equals("null")) {
							temp += " 空 " + ";";
						} else {
							temp += entry.getNewValue() + ";";
						}

					}
				}
				if (temp.length() > 0) {
					temp = temp.substring(0, temp.length() - 1);
				}
				resultList.add(temp);
			}

		}

		return resultList;
	}

	public static String getStringCompareList(List<?> compared,
			List<?> compare, Map<String, String> configMap) throws Exception {
		String resultString = "";

		List<String> list = getListCompareList(compared, compare, configMap);
		if (list.size() != 0) {
			for (String temp : list) {
				resultString += temp + ";";
			}
			resultString = resultString.substring(0, resultString.length() - 1);
		}
		return resultString;
	}

	public static Map getCompareObjectValue(String key, Class<?> classType,
			Object obj, Object obj1) throws Exception {
		Map<String, Object> resultMap = new HashMap<String, Object>();

		String[] fields = key.split("\\.");
		Class<?> tempC = classType;
		Object one = obj;
		Object two = obj1;
		Method method = null;

		for (String field : fields) {
			try {
				method = tempC.getMethod(
						"get" + field.substring(0, 1).toUpperCase()
								+ field.substring(1), new Class<?>[] {});
			} catch (Exception e) {
				method = tempC.getMethod(
						"is" + field.substring(0, 1).toUpperCase()
								+ field.substring(1), new Class<?>[] {});
			}

			one = method.invoke(one, new Class<?>[] {});
			two = method.invoke(two, new Class<?>[] {});
			tempC = method.getReturnType();
		}
		if (one instanceof Date) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			one = sdf.format(one);
			two = sdf.format(two);
		}
		resultMap.put("one", one == null ? "" : one);
		resultMap.put("two", two == null ? "" : two);
		return resultMap;
	}

	public static Object getSingleValue(String key, Class<?> classType, Object obj)
			throws Exception {

		String[] fields = key.split("\\.");
		Class<?> tempC = classType;
		Object one = obj;
		Method method = null;

		for (String field : fields) {
			try {
				method = tempC.getMethod(
						"get" + field.substring(0, 1).toUpperCase()
								+ field.substring(1), new Class<?>[] {});
			} catch (Exception e) {
				method = tempC.getMethod(
						"is" + field.substring(0, 1).toUpperCase()
								+ field.substring(1), new Class<?>[] {});
			}

			one = method.invoke(one, new Class<?>[] {});
			tempC = method.getReturnType();
		}
		if (one instanceof Date) {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			one = sdf.format(one);
		}
		return one == null ? "" : one;
	}

	private class Entry {

		private String id;// 为了标识是同一个对象发生的改变

		private String name;// 中文名

		private String oldValue;// 被比较对象的值

		private String newValue;// 比较对象的值

		private int type;// 0是删除，1是新增， 2是修改

		public String getId() {
			return id;
		}

		public void setId(String id) {
			this.id = id;
		}

		public int getType() {
			return type;
		}

		public void setType(int type) {
			this.type = type;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public String getOldValue() {
			return oldValue;
		}

		public void setOldValue(String oldValue) {
			this.oldValue = oldValue;
		}

		public String getNewValue() {
			return newValue;
		}

		public void setNewValue(String newValue) {
			this.newValue = newValue;
		}

	}
}
